#include <gtk/gtk.h>
#include <stdlib.h>

typedef enum _player
{
    x,
    o,
    none
} player;

typedef struct _tictactoe_msg
{
    player *board, *cur_player;
    int pos, *moves;
    GtkWidget *next_move;
} tictactoe_msg;

static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
    gtk_main_quit();
    return FALSE;
}

static void init_board (player *board)
{
    int i;
    for (i = 0; i < 9; i++)
    {
	board[i] = none;
    }
}

static gboolean check_win (player *board, player cp)
{
    gboolean wins = FALSE;
    
    //diagonals
    if (board[0] == cp && board[4] == cp && board[8] == cp)
	wins = TRUE;
    else if (board[2] == cp && board[4] == cp && board[6] == cp)
	wins = TRUE;
    //columns
    else if (board[0] == cp && board[3] == cp && board[6] == cp)
	wins = TRUE;
    else if (board[1] == cp && board[4] == cp && board[7] == cp)
	wins = TRUE;
    else if (board[2] == cp && board[5] == cp && board[8] == cp)
	wins = TRUE;
    //rows
    else if (board[0] == cp && board[1] == cp && board[2] == cp)
	wins = TRUE;
    else if (board[3] == cp && board[4] == cp && board[5] == cp)
	wins = TRUE;
    else if (board[6] == cp && board[7] == cp && board[8] == cp)
	wins = TRUE;

    return wins;
}

static player check_board (player *board)
{
    if (check_win (board, x))
	return x;
    else if (check_win (board, o))
	return o;
    else
	return none;
}

static void clear (GtkWidget *widget, gpointer data)
{
    gtk_button_set_label (GTK_BUTTON (widget), "");
}

static void destroy_widget (GtkWidget *widget, gpointer data)
{
    gtk_widget_destroy (GTK_WIDGET (data));
}

static void alert (const char *label_text)
{
    GtkWidget *dialog, *label, *button;
    dialog = gtk_dialog_new ();
    label = gtk_label_new (label_text);
    button = gtk_button_new_with_label ("Okay");
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0);
    g_signal_connect (G_OBJECT (button), "clicked", 
		      G_CALLBACK (destroy_widget), (gpointer) dialog);
    gtk_widget_set_size_request (dialog, 200, 100);
    gtk_window_set_title (GTK_WINDOW (dialog), "Winner!");
    gtk_widget_show (button);
    gtk_widget_show (label);
    gtk_widget_show (dialog);
}

static void gameover (tictactoe_msg *msg, player winner, GtkWidget *widget)
{
    char *label_text;
    if (winner == x) label_text = "X Wins!";
    else if (winner == o) label_text = "O Wins!";
    else label_text = "Cat's Game!";
    alert (label_text);
    init_board (msg->board);
    *(msg->moves) = 0;
    *(msg->cur_player) = x;
    gtk_container_foreach (GTK_CONTAINER (gtk_widget_get_parent (widget)), 
			   (GtkCallback) clear, NULL);
}

static void toggle_button (GtkWidget *widget, gpointer data)
{
    tictactoe_msg *msg;
    player *board;
    player winner, *cur_player;
    int *moves;
    
    msg = (tictactoe_msg *) data;
    board = msg->board;
    cur_player = msg->cur_player;
    moves = msg->moves;

    if (board[msg->pos] == none)
    {
	board[msg->pos] = *cur_player;

	if (*cur_player == x)
	{
	    *cur_player = o;
	    gtk_button_set_label (GTK_BUTTON (widget), "X");
	    gtk_label_set_text (GTK_LABEL (msg->next_move), "Next Move: O");
	}
        else
	{
	    *cur_player = x;
	    gtk_button_set_label (GTK_BUTTON (widget), "O");
	    gtk_label_set_text (GTK_LABEL (msg->next_move), "Next Move: X");
	}
	(*moves)++;
	winner = (check_board (board));
	if (winner != none)
	    gameover (msg, winner, widget);
	else if (*moves == 9)
	    gameover (msg, none, widget);
    }
}

int main (int argc, char *argv[])
{
   GtkWidget *window,
	     *table,
	     *vbox,
	     *next_move,
	     *button;
   tictactoe_msg *msg;
   int i, j, moves; 
   player board[9], cur_player;

   gtk_init (&argc, &argv);

    
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (window), "TicTacToe");
    gtk_widget_set_size_request (GTK_WIDGET (window), 200, 200);
    g_signal_connect (G_OBJECT (window), "delete_event",
		      G_CALLBACK (delete_event), NULL);
    
    vbox = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_widget_show (vbox);

    next_move = gtk_label_new ("Next Move: X");
    gtk_box_pack_start (GTK_BOX (vbox), next_move, FALSE, FALSE, 5);
    gtk_widget_show (next_move);

    table = gtk_table_new (3, 3, TRUE);
    gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
    gtk_widget_show (table);

    init_board (board);
    cur_player = x;
    moves = 0;

    for (i = 0; i < 3; i++)
    {
	for (j = 0; j < 3; j++)
	{
	    button = gtk_button_new ();
	    gtk_widget_set_size_request (GTK_WIDGET (button), 35, 35);
	    gtk_table_attach_defaults (GTK_TABLE (table), button, j, j+1, i, i+1);
	    gtk_widget_show (button);
	    msg = (tictactoe_msg *) malloc (sizeof (tictactoe_msg));
	    msg->board = board;
	    msg->pos = i * 3 + j;
	    msg->cur_player = &cur_player;
	    msg->moves = &moves;
	    msg->next_move = next_move;
	    g_signal_connect (G_OBJECT (button), "clicked",
			      G_CALLBACK (toggle_button), (gpointer) msg);

	}
    }

   gtk_widget_show (window);
   gtk_main ();
   return 0;
}  

